package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.gateway.constant.RedisConst;
import com.atguigu.gmall.model.user.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * @Author: lx
 * @Time: 15:28
 * @Description: 判断用户是否登录
 *
 * GlobalFilter : 默认有9大过滤器    SpringCloudGateWay
 *
 *   10大过滤器   == 9个默认启动 + 1个自定义过滤器
 *      路由
 *
 *
 */
@Order(0)  //排序   执行优先级 越小超先执行
@Component
public class LoginGlobalFilter implements GlobalFilter {

    //路径匹配
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Value("${auth.url}")
    private String[] authUrl;
    @Value("${login.url}")
    private String loginUrl;
    @Autowired
    private RedisTemplate redisTemplate;

    //页面 混合请求  同步请求    应该从Cookie中获取token  连接Redis 中获取用户信息
    //      异步请求 VUE Ajax    应该从请求头中获取token

    //全局请求过滤的方法
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //判断是否登录    token   Http请求的时候的请求或响应吗？
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //当前请求的路径   /list.html
        String path = request.getURI().getPath();
        System.out.println(path);
        //  //list.gmall.com/list.html?keyword=%E6%89%8B%E6%9C%BA
        System.out.println(request.getURI().getRawSchemeSpecificPart());
        //获取token
        String userId = getToken(request);

        //1：访问 搜索微服务 订单微服务 详情微服务 商品微服务 异步请求
        if (antPathMatcher.match("/**/auth/**", path)) {
            //必须登录  判断是否登录
            if(null == userId){
                //未登录 //直接返回结果 （ result 设置  LOGIN_AUTH(208, "未登陆"),
                return out(response,ResultCodeEnum.LOGIN_AUTH);
            }
        }
        //2：内部资源  网关不给访问  /api/user/inner/findAll
        if (antPathMatcher.match("/**/inner/**", path)) {
            //直接返回结果 （ result 设置  PERMISSION(209, "没有权限"),
            return out(response,ResultCodeEnum.PERMISSION);
        }
        //3：访问页面微服务的时候  同步请求
        //首页 /
        //搜索 list.html
        //商品详情 /4312412432.html
        //购物车  /cart.html
        //结算页面  /trade.html
        //订单页面 order.html
        //支付页面  pay.html
        for (String url : authUrl) {
            if (url.equals(path)) {
                //判断是否登录
                //未登录  重定向到登录页面   保存的用户信息
                if(null == userId){
                    //http://passport.gmall.com/login.html?originUrl=http%3A%2F%2Flist.gmall.com%2Flist.html%3Fkeyword%3D%25E6%2589%258B%25E6%259C%25BA
                    //response.sendRedirect
                    // 状态码  200 404 url  400 入参不正确  500   302
                    try {
                    //设置重定向的地址
                        response.getHeaders().add(HttpHeaders.LOCATION,
                                loginUrl + URLEncoder.encode(request.getURI().getRawSchemeSpecificPart(),"utf-8"));
                    //设置response支持重定向  java.net
                        response.setStatusCode(HttpStatus.SEE_OTHER);
                        return response.setComplete();
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        //购物车页面
        //已经登录了  userId 不为 null
        if(null != userId){
            //传递用户ID给后面需要转发的微服务 使用请求头
            //request.getHeaders().add("userId",userId);
            request.mutate().header("userId",userId);
        }
        //未登录 临时用户ID
        String userTempId = getUserTempId(request);
        if(null != userTempId){
            //传递用户ID给后面需要转发的微服务 使用请求头
            request.mutate().header("userTempId",userTempId);
        }
        //转发后面的微服务  登录成功之后才让正常访问
        return chain.filter(exchange);
    }

    //不允许访问时候的响应结果
    private Mono<Void> out(ServerHttpResponse response,ResultCodeEnum resultCodeEnum) {
        Result<Object> result = Result.build(null,resultCodeEnum);
        String json = JSONObject.toJSONString(result);
        DataBufferFactory dataBufferFactory = response.bufferFactory();
        DataBuffer dataBuffer = dataBufferFactory.wrap(json.getBytes());
        //响应编码
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE,"application/json;charset=utf-8");
        return response.writeWith(Mono.just(dataBuffer));
    }
    //获取用户的临时ID
    private String getUserTempId(ServerHttpRequest request){
        //1：获取请求头
        String userTempId = request.getHeaders().getFirst("userTempId");
        if(null == userTempId) {
            //2：没有 再获取Cookie
            HttpCookie cookie = request.getCookies().getFirst("userTempId");
            if (null != cookie) {
                userTempId = cookie.getValue();
            }
        }
        return userTempId;
    }

    //获取用户ID
    private String getToken(ServerHttpRequest request) {
        //1：获取请求头
        String token = request.getHeaders().getFirst("token");
        if(null == token){
            //3：没有 再获取Cookie
            HttpCookie cookie = request.getCookies().getFirst("token");
            if(null != cookie){
                String value = cookie.getValue();
                if(null != value){//7天
                    //4：有 直接使用
                    if(redisTemplate.hasKey(RedisConst.USER_LOGIN_KEY_PREFIX + value)){
                        UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().
                                get(RedisConst.USER_LOGIN_KEY_PREFIX + value);
                        return userInfo.getId().toString();
                    }
                }
            }
        }else{
            //2：有 直接使用
            if(redisTemplate.hasKey(RedisConst.USER_LOGIN_KEY_PREFIX + token)){
                UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().
                        get(RedisConst.USER_LOGIN_KEY_PREFIX + token);
                return userInfo.getId().toString();
            }
        }
        //5：没有 返回NULL
        return null;

    }




}
